package com.zzy.jdk8.lambda;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.IntSummaryStatistics;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;

import org.junit.Test;

public class LambdaTest {
	
	
	/**
	 *  list.forEach(n -> System.out.println(n));
		list.forEach(System.out::println);  // 使用方法引用
		list.forEach((String s) -> System.out.println("*" + s + "*"));
	 */

	@Test
	public void test1() {
		List<Integer> list = new ArrayList<>();
		list.add(1);
		list.add(2);
		list.add(3);
		// 直接打印
		list.forEach(System.out::println);

		// 取值分别操作
		list.forEach(  i -> {System.out.println(i * 3);}  );
		
	}

	
	/**
	 * Predicate接口
	 */
	@Test
	public void test15() {
		List<String> languages = Arrays.asList("Java", "Scala", "C++", "Haskell", "Lisp");

		System.out.println("Languages which starts with J :");
		filter(languages, (str) -> ((String) str).startsWith("J"));

		System.out.println("Languages which ends with a ");
		filter(languages, (str) -> ((String) str).endsWith("a"));

		System.out.println("Print all languages :");
		filter(languages, (str) -> true);

		System.out.println("Print no language : ");
		filter(languages, (str) -> false);

		System.out.println("Print language whose length greater than 4:");
		filter(languages, (str) -> ((String) str).length() > 4);

	}

	public static void filter(List<String> names, Predicate<String> condition) {
		for (String name : names) {
			if (condition.test(name)) {
				System.out.println(name + " ");
			}
		}
	}

	/**
	 * 通过过滤创建一个string, list
	 */
	@Test
	public void testFilter() {
		List<String> strList = Arrays.asList("abc", "eqwr", "bcd", "qb", "ehdc", "jk");
		List<String> filtered = strList.stream().filter(x -> x.length() > 2).collect(Collectors.toList());
		System.out.printf("Original List : %s, filtered list : %s %n", strList, filtered);
	}

	
	/**
	 * map, 允许将对象进行转换, 比如, 可以更改list中的每个元素的值  
	 * 使用流API的收集器类，可以得到所有含税的开销。有 toList() 这样的方法将 map 或任何其他操作的结果合并起来。
	 * //i->i+1 表示逐个加1
	 * 	 
	 */
	@Test
	public void testDistinct() {
		List<Integer> numbers = Arrays.asList(9, 10, 3, 4, 7, 3, 4);
		List<Integer> distinct = numbers.stream().map(i -> i+1).distinct().collect(Collectors.toList());
		System.out.printf("Original List : %s,  Square Without duplicates : %s %n", numbers, distinct);
	}
	
	/**
	 * 计算集合元素的最大值、最小值、总和以及平均值
       IntStream、LongStream 和 DoubleStream 等流的类中，有个非常有用的方法叫做 summaryStatistics() 。
	       可以返回 IntSummaryStatistics、LongSummaryStatistics 或者 DoubleSummaryStatistic s，描述流中元素的各种摘要数据。
	       在本例中，我们用这个方法来计算列表的最大值和最小值。它也有 getSum() 和 getAverage() 方法来获得列表的所有元素的总和及平均值。
	 */
	@Test
	public void testGroup() {
		//获取数字的个数、最小值、最大值、总和以及平均值
		List<Integer> primes = Arrays.asList(2, 3, 5, 7, 11, 13, 17, 19, 23, 29);
		IntSummaryStatistics stats = primes.stream().mapToInt((x) -> x).summaryStatistics();
		System.out.println("Highest prime number in List : " + stats.getMax());
		System.out.println("Lowest prime number in List : " + stats.getMin());
		System.out.println("Sum of all prime numbers : " + stats.getSum());
		System.out.println("Average of all prime numbers : " + stats.getAverage());
	}
	
	
	/**
	 * Map和Reduce示例
	 * 我们将 costBeforeTax 列表的每个元素转换成为税后的值。我们将 x -> x*x lambda表达式传到 map() 方法，
	 * 后者将其应用到流中的每一个元素。然后用 forEach() 将列表元素打印出来。
	 * 
	 * Map和Reduce操作是函数式编程的核心操作，因为其功能，reduce 又被称为折叠操作
	 * 。另外，reduce 并不是一个新的操作，你有可能已经在使用它。
	 * SQL中类似 sum()、avg() 或者 count() 的聚集函数，实际上就是 reduce 操作，因为它们接收多个值并返回一个值。
	 * 流API定义的 reduce() 函数可以接受lambda表达式，并对所有值进行合并
	 */
	@Test
	public void mapReduce() {
		// 不使用lambda表达式为每个订单加上12%的税
		List<Integer> costBeforeTax = Arrays.asList(100, 200, 300, 400, 500);
		for (Integer cost : costBeforeTax) {
		    double price = cost + 0.12*cost;
		    System.out.println(price);
		}
		 
		 System.out.println("---------------------------------------");
		// 使用lambda表达式
		List<Integer> costBefore= Arrays.asList(100, 200, 300, 400, 500);
		costBefore.stream().map((cost) -> cost + 0.12*cost).forEach(System.out::println);
		
		 System.out.println("---------------------------------------");
		// 新方法：
		List<Integer> costBefore2 = Arrays.asList(100, 200, 300, 400, 500);
		double bill = costBefore2.stream().map((cost) -> cost + 0.12*cost).reduce((sum, cost) -> sum + cost).get();
		System.out.println("Total : " + bill);

	}
	
	

}
